using Jupiter.Infrastructure.Attributes;
using Jupiter.Infrastructure.Cache.Interfaces;
using Jupiter.Infrastructure.Domain.SqlSugar;
using Jupiter.Infrastructure.Exceptions;
using Jupiter.Infrastructure.Permission;
using Jupiter.Infrastructure.Permission.DataPermissions;
using Jupiter.Infrastructure.Responses;
using Microsoft.Extensions.Configuration;
using Wips.AppService.Authorities.Operations;
using Wips.AppService.Authorities.Operations.Requests;
using Wips.AppService.Authorities.Operations.Responses;
using Wips.AppService.Authorities.Operations.ViewModels;
using Wips.Domain.Models.Authorities.Model;

namespace Wips.AppService.SqlSugar.Authorities.Operations;

/// <summary>
/// 操作服务接口实现类
/// </summary>
[ServiceComponent]
public class OperationService : BaseQueryAppService<Operation>, IOperationService
{
    /// <summary>
    /// 读取分页列表
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    public async Task<PageResult<GetOperationPagesResponse>> GetPagesAsync(
        GetOperationPagesRequest request)
    {
        return await QueryNoTracking()
            .Where(p => p.MenuId == request.MenuId)
            .Select(p => new GetOperationPagesResponse
            {
                Id = p.Id!,
                Name = p.Name,
                Created = p.Created,
                Updated = p.Updated,
                MenuId = p.MenuId,
                Code = p.Code,
                Sort = p.Sort
            })
            .ToPageAsync(request);
    }

    /// <summary>
    /// 读取信息
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<OperationViewModel> GetByIdAsync(string id)
    {
        return await QueryNoTracking()
            .Where(p => p.Id == id)
            .Select(p => new OperationViewModel
            {
                Id = p.Id!,
                Name = p.Name,
                MenuId = p.MenuId,
                Code = p.Code,
                Sort = p.Sort
            })
            .FirstOrDefaultAsync();
    }

    /// <summary>
    /// 读取权限代码
    /// </summary>
    /// <param name="userId">用户Id，默认为当前登录用户</param>
    /// <returns></returns>
    public async Task<List<string>> GetCodesByUserIdAsync(string? userId)
    {
        if (string.IsNullOrEmpty(userId))
        {
            if (string.IsNullOrEmpty(UserId))
            {
                throw new CoreException("用户未登录");
            }

            // 当前登录用户
            userId = UserId;
        }

        var roleIdSql = await GetUserRoleSql(userId);

        var perSql = Query<RolePermission>()
            .Where(v => roleIdSql!.Contains(v.RoleId))
            .Select(v => v.PermissionId)
            .ToSqlString();
        perSql = "   PermissionId in ( " + perSql + " )";
        var list = await QueryNoTracking<Operation>()
            .Where(a => a.Id == SqlFunc.Subqueryable<PermissionOperation>()
                .Where(c => SqlFunc.MappingColumn(default(bool), perSql))
                .GroupBy(c => c.OperationId)
                .Select(c => c.OperationId))
            .ToListAsync();

        if (list.Count == 0)
        {
            return new List<string>();
        }

        var result = new List<string>();

        // 分组去重
        foreach (var group in list.GroupBy(p => p.Id))
        {
            var first = group.FirstOrDefault();
            if (first == null)
            {
                continue;
            }

            var codes = first.Code.Split(',');

            foreach (var code in codes)
            {
                // 排除重复
                if (result.Any(c => c == code))
                {
                    continue;
                }

                result.Add(code);
            }
        }

        return result.OrderBy(code => code).ToList();
    }


    /// <summary>
    /// 根据用户版本读取菜单
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="versionIds"></param>
    /// <param name="isRoot"></param>
    /// <returns></returns>
    public async Task<List<OperationViewModel>> GetVersionsOperationAsync(string userId,
        bool isRoot = false)
    {
        var roleIdSql = isRoot ? new List<string>() : await GetUserRoleSql(userId);
        if (isRoot)
        {
            var list = await QueryNoTracking<Permission>()
                .InnerJoin<PermissionOperation>(( pe, pm) => pe.Id == pm.PermissionId)
                .Where(pe => pe.PermissionType == AuthoritiePermissionType.Operation)
                .Select((pe, pm) => new OperationViewModel()
                {
                    Id = pm.OperationId,
                    Name = pm.Operation.Name,
                    Code = pm.Operation.Code,
                    MenuId = pm.Operation.MenuId
                })
                .ToListAsync();
            return list;
        }

        else
        {
            var list = await QueryNoTracking<Permission>()
                .InnerJoin<PermissionOperation>(( pe, pm) => pe.Id == pm.PermissionId)
                .InnerJoin<RolePermission>(( pe, pm, rp) =>
                    roleIdSql!.Contains(rp.RoleId))
                .InnerJoin<Permission>(( pe, pm, rp, rpp) => rpp.Id == rp.PermissionId)
                .InnerJoin<PermissionOperation>(( pe, pm, rp, rpp, rpm) =>
                    rpm.PermissionId == rpp.Id && pm.OperationId == rpm.OperationId)
                .Where(pe =>  pe.PermissionType == AuthoritiePermissionType.Operation)
                .Select(( pe, pm) => new OperationViewModel()
                {
                    Id = pm.OperationId,
                    Name = pm.Operation.Name,
                    Code = pm.Operation.Code,
                    MenuId = pm.Operation.MenuId
                })
                .ToListAsync();
            return list;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="dbContext"></param>
    /// <param name="securityContextAccessor"></param>
    /// <param name="configuration"></param>
    /// <param name="cacheManager"></param>
    /// <param name="dataPermission"></param>
    public OperationService(ISqlSugarClient dbContext, ISecurityContextAccessor securityContextAccessor,
        IConfiguration? configuration, ICacheManager cacheManager, IDataPermission dataPermission) : base(dbContext,
        securityContextAccessor, configuration, cacheManager, dataPermission)
    {
    }
}